#pragma once
#include<iostream>
#include<unordered_map>
#include<string>
#include<sys/epoll.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>

class EventItem;
class Reactor;
typedef void(*callback_t)(EventItem&);

class EventItem
{
public:
    int sock_;
    Reactor* R_;

    callback_t recv_handler;
    callback_t send_handler;
    callback_t error_handler;

    std::string inbuffer;
    std::string outbuffer;
public:
    EventItem():sock_(-1),R_(nullptr),recv_handler(nullptr),send_handler(nullptr),error_handler(nullptr)
    {}
    void RegisterCallBacks(callback_t recv,callback_t send,callback_t error)
    {
        recv_handler = recv;
        send_handler = send;
        error_handler = error;
    }
};
class Reactor
{
private:
    int epfd_;
    std::unordered_map<int,EventItem> event_items;
    int size;
public:
    Reactor(int s = 128):epfd_(-1),size(s){}
    void Init()
    {
        epfd_ = epoll_create(size);
        if(epfd_ < 0)
        {
            std::cerr << "epoll create error" << std::endl;
            exit(3);
        }
    }
    void Dispatcher(int timeout)
    {
        struct epoll_event revs[size];
        int num = epoll_wait(epfd_,revs,size,timeout);
        for(int i = 0; i < num; ++i)
        {
            int sock = revs[i].data.fd;
            if( (revs[i].events&EPOLLERR) || (revs[i].events&EPOLLHUP) )
                if(event_items[sock].error_handler)
                    event_items[sock].error_handler(event_items[sock]);
            if(revs[i].events&EPOLLIN)
                if(event_items[sock].recv_handler)
                    event_items[sock].recv_handler(event_items[sock]);
            if(revs[i].events&EPOLLOUT)
                if(event_items[sock].send_handler)
                    event_items[sock].send_handler(event_items[sock]);
        }
    }
    void AddEvent(int sock,size_t event,const EventItem& item)
    {
        struct epoll_event ev;
        ev.data.fd = sock;
        ev.events = event;

        if(epoll_ctl(epfd_,EPOLL_CTL_ADD,sock,&ev) < 0)
            std::cerr << "epoll ctl add error" << std::endl;
        else
        {
            event_items.insert(std::make_pair(sock,item));
            std::cout << "添加：" << sock << " 到epoll模型中" << std::endl;
        }
    }
    void DelEvent(int sock)
    {
        if(epoll_ctl(epfd_,EPOLL_CTL_DEL,sock,nullptr) < 0)
            std::cerr << "epoll ctl del error" << std::endl;
        else
        {
            event_items.erase(sock);
            std::cout << "从epoll模型中删除：" << sock << std::endl;
        }
    }
    void EnableReadWrite(int sock,bool read,bool write)
    {
        struct epoll_event ev;
        ev.data.fd = sock;
        ev.events = (read ? EPOLLIN : 0) | (write ? EPOLLOUT : 0) | EPOLLET;
        if(epoll_ctl(epfd_,EPOLL_CTL_MOD,sock,&ev) < 0)
            std::cerr << "epoll ctl mod error,fd:" << sock << std::endl;
    }
    ~Reactor()
    {
        if(epfd_ >= 0)
            close(epfd_);
    }
};